Idé: eigen value compression för att få fram bakgrund

MVP: - Bakgrundsmodel 1. Average över frames på samma klipp, differencing / threshold 2. Average över frames flera klipp 3. Gaussian, över sigma 4. Frame differencing - Priors 1. Uniform 2. Parametrisk x, y, k, size från heat map 3. Conditional på förra framen - Likelihood 1. Rektangel överlapp 2. Ellips överlapp 3. Parametriska människoformer - Proposal 1. Uniform 2. K-means på pixlar / ellipsfitting - Accuracy 1. Antal personer 2. Antal personer + överlapp 3. Antal personer + labels - Över frames 1. Inget 2. Drift / diffusion

library(jpeg)
jj <- readJPEG("./mall_dataset/frames/seq_000001.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)

w <- 640
h <- 480

jj[seq(100, 1000)] = rep(1, 901)
jj[seq(100, 1000) + w*h] = rep(0, 901)
jj[seq(100, 1000) + 2*w*h] = rep(0, 901)


rasterImage(jj,0,0,1,1)
library(rmatio)
ground_truth <- read.mat("./mall_dataset/mall_gt.mat")


# ground_truth$frame[[1]][[2000]]$loc[[1]][,1]

jj <- readJPEG("./mall_dataset/frames/seq_000001.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)

rasterImage(jj,0,0,1,1)

points(ground_truth$frame[[1]][[1]]$loc[[1]][,1] / w, 1-ground_truth$frame[[1]][[1]]$loc[[1]][,2] / h)
jpgs <- list()
# frames <- 2000
frames <- 1000
# background <- rep(0, w*h*3)
background <- jj / frames
for (f in 2:frames) {
  jpg <- readJPEG(paste("./mall_dataset/frames/seq_",strrep("0", 6-log10(f + 1)),f,".jpg", sep=""),native=FALSE)
  # for (i in 1:(w*h*3)) {
  for (i in 1:h) {
    for (j in 1:w) {
      for (c in 1:3) {
        background[i, j, c] <- background[i, j, c] + jpg[i, j, c] / frames
      }
    }
  }
}

for (i in 1:h) {
  for (j in 1:w) {
    for (c in 1:3) {
        background[i, j, c] <- max(min(background[i, j, c], 1), 0)
    }
  }
}
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
# rasterImage(background,0,0,1,1)
rasterImage(background,0,0,1,1)
# jj <- readJPEG("./mall_dataset/frames/seq_000001.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)

rasterImage(jj,0,0,1,1)

locs <- list()

for (f in 1:frames) {
  points(ground_truth$frame[[1]][[f]]$loc[[1]][,1] / w, 1-ground_truth$frame[[1]][[f]]$loc[[1]][,2] / h)
}
jj <- readJPEG("./mall_dataset/frames/seq_000001.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)

interp <- function(x) -20*x^7+70*x^6-84*x^5+35*x^4

for (i in 1:h) {
  for (j in 1:w) {
    # for (c in 1:3) {
        # jj[i, j, c] <- max(min(jj[i, j, c] - background[i, j, c], 1), 0)
        # jj[i, j, c] <- max(min(-(sum(jj[i, j, c(1,2,3)])/3 - sum(background[i, j, c(1,2,3)])/3), 1), 0)
        # jj[i, j, c] <- max(min(mean(jj[i, j, c(1,2,3)]), 1), 0)
        # jj[i, j, c(1,2,3)] <- max(min(interp(1-(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)]))), 1), 0)
        jj[i, j, c(1,2,3)] <- max(min(
          # ifelse(abs(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)])) < 0.1, 0, mean(jj[i, j, c(1,2,3)]))
          ifelse(abs(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)])) < 0.1, 0, 1)
        , 1), 0)
    # }
  }
}

rasterImage(jj,0,0,1,1)
# points(ground_truth$frame[[1]][[1]]$loc[[1]][,1] / w, 1-ground_truth$frame[[1]][[1]]$loc[[1]][,2] / h, col="red")
jj <- readJPEG("./mall_dataset/frames/seq_000001.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(jj,0,0,1,1)

plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(background,0,0,1,1)
r <- c()
g <- c()
# frames <- 2000
frames <- 1000
i <- 200
j <- 300
# background <- rep(0, w*h*3)
for (f in 1:frames) {
  jpg <- readJPEG(paste("./mall_dataset/frames/seq_",strrep("0", 6-log10(f + 1)),f,".jpg", sep=""),native=FALSE)
  # for (i in 1:(w*h*3)) {
  # for (i in 1:h) {
    # for (j in 1:w) {

      r <- c(r, jpg[i, j, 1])
      g <- c(g, jpg[i, j, 2])
    # }
  # }
}

plot(r, g, xlim=c(0,1), ylim=c(0,1))
frames <- seq(1, 2000, by=2000/200)
frame_paths <- paste0("./mall_dataset/frames/seq_",strrep("0", 6-log10(frames + 1)),frames,".jpg")
# frames <- paste0("./mall_dataset/frames/seq_",strrep("0", 6-log10(1:100 + 1)),1:100,".jpg")
library(magick)
m <- image_read(frame_paths)
m <- image_animate(m)
image_write(m, "./movie10.gif")
library(jpeg)
jj <- readJPEG("./caviar_frames/ThreePastShop1cor0000.jpg",native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)

w <- 348
h <- 288

# jj[seq(100, 1000)] = rep(1, 901)
# jj[seq(100, 1000) + w*h] = rep(0, 901)
# jj[seq(100, 1000) + 2*w*h] = rep(0, 901)


rasterImage(jj,0,0,1,1)

library(XML)
# library(methods)

# f <- 500
# f <- 1200
for (f in round(seq(2, 1000, length.out = 100))) {
# jj <- readJPEG(paste("./caviar_frames/ThreePastShop1cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
jj <- readJPEG(paste("./caviar_frames2/TwoEnterShop2cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)

# result <- xmlParse(file = "./c3ps1gt.xml")
result <- xmlParse(file = "./c2es2gt.xml")

# print(result)

plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(jj,0,0,1,1)

rootnode <- xmlRoot(result)
is<-1:length(xmlElementsByTagName(rootnode[[f]][[1]], "object"))
for (i in is) {
  attrs <- xmlAttrs(rootnode[[f]][[1]][[i]][[2]])
  box <- list(
    w=as.numeric(attrs["w"]),
    h=as.numeric(attrs["h"]),
    x=as.numeric(attrs["xc"]),
    y=as.numeric(attrs["yc"]),
    xy = c(as.numeric(attrs["xc"]), as.numeric(attrs["yc"]))
  )
  box
  
  rect((box$x - box$w/2) / w, 1-(box$y - box$h/2) / h, (box$x + box$w/2)/w, 1-(box$y + box$h/2)/h)
}

}

NA
NA
# rect((box$x-box$w/4) / w, 1-(box$y - box$h/2) / h, (box$x-box$w/4)/w, 1-(box$y + box$h/2)/h)
# points(box$x/w, 1-box$y/h, col="green")
# points((box$x-box$w)/w, 1-box$y/h, col="red")
# points((box$x-box$w/2)/w, 1-box$y/h, col="red")
# points((box$x+box$w)/w, 1-box$y/h, col="red")
# points((box$x+box$w/2)/w, 1-box$y/h, col="red")
# 
# points((box$x)/w, 1-(box$y-box$h/2)/h, col="red")
# points((box$x)/w, 1-(box$y-box$h)/h, col="red")
# points((box$x)/w, 1-(box$y+box$h/2)/h, col="red")
# points((box$x)/w, 1-(box$y+box$h)/h, col="red")
# 
# p1 <- c(91-10,163)
# # p2 <- c(91/w,163/h)
# p3 <- c(98-10,266)
# p4 <- c(322-10,265)
# 
# points(p1[1]/w, 1-p1[2]/h, col="orange")
# points(p3[1]/w, 1-p3[2]/h, col="orange")
# points(p4[1]/w, 1-p4[2]/h, col="orange")

# Y <- (p1-p3)
# # Y <- (p3-p1)
# Y <- Y/norm(Y, type="2")
# X <- p4-p3
# X <- X/norm(X, type="2")
# 
# # points(box$xy%*%X/w, 1-box$xy%*%Y/h, col="green")
# p <- box$x%*%X + box$y%*%Y
# points(p[1]/w, 1-p[2]/h, col="blue")

# lines(rep(0.5, 100), seq(0.01, 1, 0.01))

# pp <- c(seq(from=0*Y[1], to=1*Y[1], length.out = 100), seq(from=0*Y[2], to=1*Y[2], length.out = 100))
# # pp <- rep(0.5*X, 100) + c(seq(from=0*Y[1], to=1*Y[1], length.out = 100), seq(from=0*Y[2], to=1*Y[2], length.out = 100))
# lines(pp[seq(1, 200, by=2)], 1-pp[seq(2, 200, by=2)])
# %*%

# plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
# for (t in seq(0, 1, by=0.01)) {
# t <- seq(0, h/2, by=0.01)
# s <- seq(0, w/2, by=0.01)
# 
# for (t in seq(0, h/2, length.out = 20)) {
#   for (s in seq(0, w/2, length.out = 20)) {
#     p <- Y*t + X*s
#     # p <- Y*t
#     # points(p[1]/w + p3[1]/w, 1-(p[2] + p3[2])/h)
#     points(p[1]/w, -(p[2])/h)
#     # points(p[1]/w + p3[1]/w, 1-(Y[2]*t/h + p3[2])/h)
#     # points(Y[1]*t/w+ p3[1]/w, 1-(Y[2]*t+ p3[2])/h)
#   }
# }
# p <- X*box$x + Y*box$y
# # # p <- Y*t
# points(p[1]/w, -(p[2])/h, col="purple")
# points(0/w, h/h, col="purple")


# points(Y[1]*t/w+ p3[1]/w, 1-(Y[2]*t+ p3[2])/h)
# points(Y[1]*t/w+ p3[1]/w, 1-(Y[2]*t+ p3[2])/h)
# points(Y[1]*box$y/w+ p3[1]/w, 1-(Y[2]*box$y+ p3[2])/h)


# points(((p1-p3)[1]*t)/w, 1-((p1-p3)[2]*t)/h, col="green")
# }
# frames <- 2000
frames <- round(seq(2, 1600, length.out = 100))
# background <- rep(0, w*h*3)
jj <- readJPEG("./caviar_frames/ThreePastShop1cor0000.jpg",native=FALSE)
background <- jj / length(frames)
for (f in frames) {
# jj <- readJPEG(paste("./caviar_frames/ThreePastShop1cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
  jpg <- readJPEG(paste("./caviar_frames2/TwoEnterShop2cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
  # for (i in 1:(w*h*3)) {
  for (i in 1:h) {
    for (j in 1:w) {
      for (c in 1:3) {
        background[i, j, c] <- background[i, j, c] + jpg[i, j, c] / length(frames)
      }
    }
  }
}

for (i in 1:h) {
  for (j in 1:w) {
    for (c in 1:3) {
        background[i, j, c] <- max(min(background[i, j, c], 1), 0)
    }
  }
}
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
# rasterImage(background,0,0,1,1)
rasterImage(background,0,0,1,1)

for (f in round(seq(2, 1600, length.out = 10))) {
# jj <- readJPEG(paste("./caviar_frames/ThreePastShop1cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
jj <- readJPEG(paste("./caviar_frames2/TwoEnterShop2cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(jj,0,0,1,1)

interp <- function(x) -20*x^7+70*x^6-84*x^5+35*x^4

for (i in 1:h) {
  for (j in 1:w) {
    # for (c in 1:3) {
        # jj[i, j, c] <- max(min(jj[i, j, c] - background[i, j, c], 1), 0)
        # jj[i, j, c] <- max(min(-(sum(jj[i, j, c(1,2,3)])/3 - sum(background[i, j, c(1,2,3)])/3), 1), 0)
        # jj[i, j, c] <- max(min(mean(jj[i, j, c(1,2,3)]), 1), 0)
        # jj[i, j, c(1,2,3)] <- max(min(interp(1-(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)]))), 1), 0)
        jj[i, j, c(1,2,3)] <- max(min(
          # ifelse(abs(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)])) < 0.1, 0, mean(jj[i, j, c(1,2,3)]))
          ifelse(abs(mean(jj[i, j, c(1,2,3)])-mean(background[i, j, c(1,2,3)])) < 0.2, 0, 1)
        , 1), 0)
    # }
  }
}

plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(jj,0,0,1,1)
# points(ground_truth$frame[[1]][[1]]$loc[[1]][,1] / w, 1-ground_truth$frame[[1]][[1]]$loc[[1]][,2] / h, col="red")
}

# library(methods)

# f <- 500
# f <- 1200
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(background,0,0,1,1)

result <- xmlParse(file = "./c2es2gt.xml")
rootnode <- xmlRoot(result)

for (f in round(seq(2, 1600, 1))) {
# jj <- readJPEG(paste("./caviar_frames/ThreePastShop1cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)
# jj <- readJPEG(paste("./caviar_frames2/TwoEnterShop2cor",strrep("0", 4-log10(f-1 + 1)),f-1,".jpg", sep=""), native=FALSE)

# result <- xmlParse(file = "./c3ps1gt.xml")

is<-1:length(xmlElementsByTagName(rootnode[[f]][[1]], "object"))
for (i in is) {
  attrs <- xmlAttrs(rootnode[[f]][[1]][[i]][[2]])
  box <- list(
    w=as.numeric(attrs["w"]),
    h=as.numeric(attrs["h"]),
    x=as.numeric(attrs["xc"]),
    y=as.numeric(attrs["yc"]),
    xy = c(as.numeric(attrs["xc"]), as.numeric(attrs["yc"]))
  )
  # box
  
  points(box$x/w, 1-box$y/h)
  
  # rect((box$x - box$w/2) / w, 1-(box$y - box$h/2) / h, (box$x + box$w/2)/w, 1-(box$y + box$h/2)/h)
}

}

NA
NA
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJZMOpOiBlaWdlbiB2YWx1ZSBjb21wcmVzc2lvbiBmw7ZyIGF0dCBmw6UgZnJhbSBiYWtncnVuZCANCg0KTVZQOg0KLSBCYWtncnVuZHNtb2RlbA0KICAxLiBBdmVyYWdlIMO2dmVyIGZyYW1lcyBww6Ugc2FtbWEga2xpcHAsIGRpZmZlcmVuY2luZyAvIHRocmVzaG9sZA0KICAyLiBBdmVyYWdlIMO2dmVyIGZyYW1lcyBmbGVyYSBrbGlwcA0KICAzLiBHYXVzc2lhbiwgw7Z2ZXIgc2lnbWENCiAgNC4gRnJhbWUgZGlmZmVyZW5jaW5nDQotIFByaW9ycw0KICAxLiBVbmlmb3JtDQogIDIuIFBhcmFtZXRyaXNrIHgsIHksIGssIHNpemUgZnLDpW4gaGVhdCBtYXANCiAgMy4gQ29uZGl0aW9uYWwgcMOlIGbDtnJyYSBmcmFtZW4NCi0gTGlrZWxpaG9vZA0KICAxLiBSZWt0YW5nZWwgw7Z2ZXJsYXBwDQogIDIuIEVsbGlwcyDDtnZlcmxhcHANCiAgMy4gUGFyYW1ldHJpc2thIG3DpG5uaXNrb2Zvcm1lcg0KLSBQcm9wb3NhbA0KICAxLiBVbmlmb3JtDQogIDIuIEstbWVhbnMgcMOlIHBpeGxhciAvIGVsbGlwc2ZpdHRpbmcgDQotIEFjY3VyYWN5DQogIDEuIEFudGFsIHBlcnNvbmVyDQogIDIuIEFudGFsIHBlcnNvbmVyICsgw7Z2ZXJsYXBwDQogIDMuIEFudGFsIHBlcnNvbmVyICsgbGFiZWxzDQotIMOWdmVyIGZyYW1lcw0KICAxLiBJbmdldA0KICAyLiBEcmlmdCAvIGRpZmZ1c2lvbg0KDQpgYGB7cn0NCmxpYnJhcnkoanBlZykNCmpqIDwtIHJlYWRKUEVHKCIuL21hbGxfZGF0YXNldC9mcmFtZXMvc2VxXzAwMDAwMS5qcGciLG5hdGl2ZT1GQUxTRSkNCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkNCg0KdyA8LSA2NDANCmggPC0gNDgwDQoNCmpqW3NlcSgxMDAsIDEwMDApXSA9IHJlcCgxLCA5MDEpDQpqaltzZXEoMTAwLCAxMDAwKSArIHcqaF0gPSByZXAoMCwgOTAxKQ0Kampbc2VxKDEwMCwgMTAwMCkgKyAyKncqaF0gPSByZXAoMCwgOTAxKQ0KDQoNCnJhc3RlckltYWdlKGpqLDAsMCwxLDEpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHJtYXRpbykNCmdyb3VuZF90cnV0aCA8LSByZWFkLm1hdCgiLi9tYWxsX2RhdGFzZXQvbWFsbF9ndC5tYXQiKQ0KDQoNCiMgZ3JvdW5kX3RydXRoJGZyYW1lW1sxXV1bWzIwMDBdXSRsb2NbWzFdXVssMV0NCg0KamogPC0gcmVhZEpQRUcoIi4vbWFsbF9kYXRhc2V0L2ZyYW1lcy9zZXFfMDAwMDAxLmpwZyIsbmF0aXZlPUZBTFNFKQ0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KDQpyYXN0ZXJJbWFnZShqaiwwLDAsMSwxKQ0KDQpwb2ludHMoZ3JvdW5kX3RydXRoJGZyYW1lW1sxXV1bWzFdXSRsb2NbWzFdXVssMV0gLyB3LCAxLWdyb3VuZF90cnV0aCRmcmFtZVtbMV1dW1sxXV0kbG9jW1sxXV1bLDJdIC8gaCkNCmBgYA0KDQpgYGB7cn0NCmpwZ3MgPC0gbGlzdCgpDQojIGZyYW1lcyA8LSAyMDAwDQpmcmFtZXMgPC0gMTAwMA0KIyBiYWNrZ3JvdW5kIDwtIHJlcCgwLCB3KmgqMykNCmJhY2tncm91bmQgPC0gamogLyBmcmFtZXMNCmZvciAoZiBpbiAyOmZyYW1lcykgew0KICBqcGcgPC0gcmVhZEpQRUcocGFzdGUoIi4vbWFsbF9kYXRhc2V0L2ZyYW1lcy9zZXFfIixzdHJyZXAoIjAiLCA2LWxvZzEwKGYgKyAxKSksZiwiLmpwZyIsIHNlcD0iIiksbmF0aXZlPUZBTFNFKQ0KICAjIGZvciAoaSBpbiAxOih3KmgqMykpIHsNCiAgZm9yIChpIGluIDE6aCkgew0KICAgIGZvciAoaiBpbiAxOncpIHsNCiAgICAgIGZvciAoYyBpbiAxOjMpIHsNCiAgICAgICAgYmFja2dyb3VuZFtpLCBqLCBjXSA8LSBiYWNrZ3JvdW5kW2ksIGosIGNdICsganBnW2ksIGosIGNdIC8gZnJhbWVzDQogICAgICB9DQogICAgfQ0KICB9DQp9DQoNCmZvciAoaSBpbiAxOmgpIHsNCiAgZm9yIChqIGluIDE6dykgew0KICAgIGZvciAoYyBpbiAxOjMpIHsNCiAgICAgICAgYmFja2dyb3VuZFtpLCBqLCBjXSA8LSBtYXgobWluKGJhY2tncm91bmRbaSwgaiwgY10sIDEpLCAwKQ0KICAgIH0NCiAgfQ0KfQ0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KIyByYXN0ZXJJbWFnZShiYWNrZ3JvdW5kLDAsMCwxLDEpDQpyYXN0ZXJJbWFnZShiYWNrZ3JvdW5kLDAsMCwxLDEpDQpgYGANCg0KYGBge3J9DQojIGpqIDwtIHJlYWRKUEVHKCIuL21hbGxfZGF0YXNldC9mcmFtZXMvc2VxXzAwMDAwMS5qcGciLG5hdGl2ZT1GQUxTRSkNCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkNCg0KcmFzdGVySW1hZ2UoamosMCwwLDEsMSkNCg0KbG9jcyA8LSBsaXN0KCkNCg0KZm9yIChmIGluIDE6ZnJhbWVzKSB7DQogIHBvaW50cyhncm91bmRfdHJ1dGgkZnJhbWVbWzFdXVtbZl1dJGxvY1tbMV1dWywxXSAvIHcsIDEtZ3JvdW5kX3RydXRoJGZyYW1lW1sxXV1bW2ZdXSRsb2NbWzFdXVssMl0gLyBoKQ0KfQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmpqIDwtIHJlYWRKUEVHKCIuL21hbGxfZGF0YXNldC9mcmFtZXMvc2VxXzAwMDAwMS5qcGciLG5hdGl2ZT1GQUxTRSkNCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkNCg0KaW50ZXJwIDwtIGZ1bmN0aW9uKHgpIC0yMCp4XjcrNzAqeF42LTg0KnheNSszNSp4XjQNCg0KZm9yIChpIGluIDE6aCkgew0KICBmb3IgKGogaW4gMTp3KSB7DQogICAgIyBmb3IgKGMgaW4gMTozKSB7DQogICAgICAgICMgampbaSwgaiwgY10gPC0gbWF4KG1pbihqaltpLCBqLCBjXSAtIGJhY2tncm91bmRbaSwgaiwgY10sIDEpLCAwKQ0KICAgICAgICAjIGpqW2ksIGosIGNdIDwtIG1heChtaW4oLShzdW0oampbaSwgaiwgYygxLDIsMyldKS8zIC0gc3VtKGJhY2tncm91bmRbaSwgaiwgYygxLDIsMyldKS8zKSwgMSksIDApDQogICAgICAgICMgampbaSwgaiwgY10gPC0gbWF4KG1pbihtZWFuKGpqW2ksIGosIGMoMSwyLDMpXSksIDEpLCAwKQ0KICAgICAgICAjIGpqW2ksIGosIGMoMSwyLDMpXSA8LSBtYXgobWluKGludGVycCgxLShtZWFuKGpqW2ksIGosIGMoMSwyLDMpXSktbWVhbihiYWNrZ3JvdW5kW2ksIGosIGMoMSwyLDMpXSkpKSwgMSksIDApDQogICAgICAgIGpqW2ksIGosIGMoMSwyLDMpXSA8LSBtYXgobWluKA0KICAgICAgICAgICMgaWZlbHNlKGFicyhtZWFuKGpqW2ksIGosIGMoMSwyLDMpXSktbWVhbihiYWNrZ3JvdW5kW2ksIGosIGMoMSwyLDMpXSkpIDwgMC4xLCAwLCBtZWFuKGpqW2ksIGosIGMoMSwyLDMpXSkpDQogICAgICAgICAgaWZlbHNlKGFicyhtZWFuKGpqW2ksIGosIGMoMSwyLDMpXSktbWVhbihiYWNrZ3JvdW5kW2ksIGosIGMoMSwyLDMpXSkpIDwgMC4xLCAwLCAxKQ0KICAgICAgICAsIDEpLCAwKQ0KICAgICMgfQ0KICB9DQp9DQoNCnJhc3RlckltYWdlKGpqLDAsMCwxLDEpDQojIHBvaW50cyhncm91bmRfdHJ1dGgkZnJhbWVbWzFdXVtbMV1dJGxvY1tbMV1dWywxXSAvIHcsIDEtZ3JvdW5kX3RydXRoJGZyYW1lW1sxXV1bWzFdXSRsb2NbWzFdXVssMl0gLyBoLCBjb2w9InJlZCIpDQpgYGANCmBgYHtyfQ0KamogPC0gcmVhZEpQRUcoIi4vbWFsbF9kYXRhc2V0L2ZyYW1lcy9zZXFfMDAwMDAxLmpwZyIsbmF0aXZlPUZBTFNFKQ0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KcmFzdGVySW1hZ2UoamosMCwwLDEsMSkNCg0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KcmFzdGVySW1hZ2UoYmFja2dyb3VuZCwwLDAsMSwxKQ0KYGBgDQoNCmBgYHtyfQ0KciA8LSBjKCkNCmcgPC0gYygpDQojIGZyYW1lcyA8LSAyMDAwDQpmcmFtZXMgPC0gMTAwMA0KaSA8LSAyMDANCmogPC0gMzAwDQojIGJhY2tncm91bmQgPC0gcmVwKDAsIHcqaCozKQ0KZm9yIChmIGluIDE6ZnJhbWVzKSB7DQogIGpwZyA8LSByZWFkSlBFRyhwYXN0ZSgiLi9tYWxsX2RhdGFzZXQvZnJhbWVzL3NlcV8iLHN0cnJlcCgiMCIsIDYtbG9nMTAoZiArIDEpKSxmLCIuanBnIiwgc2VwPSIiKSxuYXRpdmU9RkFMU0UpDQogICMgZm9yIChpIGluIDE6KHcqaCozKSkgew0KICAjIGZvciAoaSBpbiAxOmgpIHsNCiAgICAjIGZvciAoaiBpbiAxOncpIHsNCg0KICAgICAgciA8LSBjKHIsIGpwZ1tpLCBqLCAxXSkNCiAgICAgIGcgPC0gYyhnLCBqcGdbaSwgaiwgMl0pDQogICAgIyB9DQogICMgfQ0KfQ0KDQpwbG90KHIsIGcsIHhsaW09YygwLDEpLCB5bGltPWMoMCwxKSkNCmBgYA0KDQpgYGB7cn0NCmZyYW1lcyA8LSBzZXEoMSwgMjAwMCwgYnk9MjAwMC8yMDApDQpmcmFtZV9wYXRocyA8LSBwYXN0ZTAoIi4vbWFsbF9kYXRhc2V0L2ZyYW1lcy9zZXFfIixzdHJyZXAoIjAiLCA2LWxvZzEwKGZyYW1lcyArIDEpKSxmcmFtZXMsIi5qcGciKQ0KIyBmcmFtZXMgPC0gcGFzdGUwKCIuL21hbGxfZGF0YXNldC9mcmFtZXMvc2VxXyIsc3RycmVwKCIwIiwgNi1sb2cxMCgxOjEwMCArIDEpKSwxOjEwMCwiLmpwZyIpDQpsaWJyYXJ5KG1hZ2ljaykNCm0gPC0gaW1hZ2VfcmVhZChmcmFtZV9wYXRocykNCm0gPC0gaW1hZ2VfYW5pbWF0ZShtKQ0KaW1hZ2Vfd3JpdGUobSwgIi4vbW92aWUxMC5naWYiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShqcGVnKQ0KamogPC0gcmVhZEpQRUcoIi4vY2F2aWFyX2ZyYW1lcy9UaHJlZVBhc3RTaG9wMWNvcjAwMDAuanBnIixuYXRpdmU9RkFMU0UpDQpwbG90KDA6MSwwOjEsdHlwZT0ibiIsYW5uPUZBTFNFLGF4ZXM9RkFMU0UpDQoNCncgPC0gMzQ4DQpoIDwtIDI4OA0KDQojIGpqW3NlcSgxMDAsIDEwMDApXSA9IHJlcCgxLCA5MDEpDQojIGpqW3NlcSgxMDAsIDEwMDApICsgdypoXSA9IHJlcCgwLCA5MDEpDQojIGpqW3NlcSgxMDAsIDEwMDApICsgMip3KmhdID0gcmVwKDAsIDkwMSkNCg0KDQpyYXN0ZXJJbWFnZShqaiwwLDAsMSwxKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShYTUwpDQojIGxpYnJhcnkobWV0aG9kcykNCg0KIyBmIDwtIDUwMA0KIyBmIDwtIDEyMDANCmZvciAoZiBpbiByb3VuZChzZXEoMiwgMTYwMCwgbGVuZ3RoLm91dCA9IDEwMCkpKSB7DQojIGpqIDwtIHJlYWRKUEVHKHBhc3RlKCIuL2Nhdmlhcl9mcmFtZXMvVGhyZWVQYXN0U2hvcDFjb3IiLHN0cnJlcCgiMCIsIDQtbG9nMTAoZi0xICsgMSkpLGYtMSwiLmpwZyIsIHNlcD0iIiksIG5hdGl2ZT1GQUxTRSkNCmpqIDwtIHJlYWRKUEVHKHBhc3RlKCIuL2Nhdmlhcl9mcmFtZXMyL1R3b0VudGVyU2hvcDJjb3IiLHN0cnJlcCgiMCIsIDQtbG9nMTAoZi0xICsgMSkpLGYtMSwiLmpwZyIsIHNlcD0iIiksIG5hdGl2ZT1GQUxTRSkNCg0KIyByZXN1bHQgPC0geG1sUGFyc2UoZmlsZSA9ICIuL2MzcHMxZ3QueG1sIikNCnJlc3VsdCA8LSB4bWxQYXJzZShmaWxlID0gIi4vYzJlczJndC54bWwiKQ0KDQojIHByaW50KHJlc3VsdCkNCg0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KcmFzdGVySW1hZ2UoamosMCwwLDEsMSkNCg0Kcm9vdG5vZGUgPC0geG1sUm9vdChyZXN1bHQpDQppczwtMTpsZW5ndGgoeG1sRWxlbWVudHNCeVRhZ05hbWUocm9vdG5vZGVbW2ZdXVtbMV1dLCAib2JqZWN0IikpDQpmb3IgKGkgaW4gaXMpIHsNCiAgYXR0cnMgPC0geG1sQXR0cnMocm9vdG5vZGVbW2ZdXVtbMV1dW1tpXV1bWzJdXSkNCiAgYm94IDwtIGxpc3QoDQogICAgdz1hcy5udW1lcmljKGF0dHJzWyJ3Il0pLA0KICAgIGg9YXMubnVtZXJpYyhhdHRyc1siaCJdKSwNCiAgICB4PWFzLm51bWVyaWMoYXR0cnNbInhjIl0pLA0KICAgIHk9YXMubnVtZXJpYyhhdHRyc1sieWMiXSksDQogICAgeHkgPSBjKGFzLm51bWVyaWMoYXR0cnNbInhjIl0pLCBhcy5udW1lcmljKGF0dHJzWyJ5YyJdKSkNCiAgKQ0KICBib3gNCiAgDQogIHJlY3QoKGJveCR4IC0gYm94JHcvMikgLyB3LCAxLShib3gkeSAtIGJveCRoLzIpIC8gaCwgKGJveCR4ICsgYm94JHcvMikvdywgMS0oYm94JHkgKyBib3gkaC8yKS9oKQ0KfQ0KDQp9DQoNCg0KYGBgDQoNCmBgYHtyfQ0KIyByZWN0KChib3gkeC1ib3gkdy80KSAvIHcsIDEtKGJveCR5IC0gYm94JGgvMikgLyBoLCAoYm94JHgtYm94JHcvNCkvdywgMS0oYm94JHkgKyBib3gkaC8yKS9oKQ0KIyBwb2ludHMoYm94JHgvdywgMS1ib3gkeS9oLCBjb2w9ImdyZWVuIikNCiMgcG9pbnRzKChib3gkeC1ib3gkdykvdywgMS1ib3gkeS9oLCBjb2w9InJlZCIpDQojIHBvaW50cygoYm94JHgtYm94JHcvMikvdywgMS1ib3gkeS9oLCBjb2w9InJlZCIpDQojIHBvaW50cygoYm94JHgrYm94JHcpL3csIDEtYm94JHkvaCwgY29sPSJyZWQiKQ0KIyBwb2ludHMoKGJveCR4K2JveCR3LzIpL3csIDEtYm94JHkvaCwgY29sPSJyZWQiKQ0KIyANCiMgcG9pbnRzKChib3gkeCkvdywgMS0oYm94JHktYm94JGgvMikvaCwgY29sPSJyZWQiKQ0KIyBwb2ludHMoKGJveCR4KS93LCAxLShib3gkeS1ib3gkaCkvaCwgY29sPSJyZWQiKQ0KIyBwb2ludHMoKGJveCR4KS93LCAxLShib3gkeStib3gkaC8yKS9oLCBjb2w9InJlZCIpDQojIHBvaW50cygoYm94JHgpL3csIDEtKGJveCR5K2JveCRoKS9oLCBjb2w9InJlZCIpDQojIA0KIyBwMSA8LSBjKDkxLTEwLDE2MykNCiMgIyBwMiA8LSBjKDkxL3csMTYzL2gpDQojIHAzIDwtIGMoOTgtMTAsMjY2KQ0KIyBwNCA8LSBjKDMyMi0xMCwyNjUpDQojIA0KIyBwb2ludHMocDFbMV0vdywgMS1wMVsyXS9oLCBjb2w9Im9yYW5nZSIpDQojIHBvaW50cyhwM1sxXS93LCAxLXAzWzJdL2gsIGNvbD0ib3JhbmdlIikNCiMgcG9pbnRzKHA0WzFdL3csIDEtcDRbMl0vaCwgY29sPSJvcmFuZ2UiKQ0KDQojIFkgPC0gKHAxLXAzKQ0KIyAjIFkgPC0gKHAzLXAxKQ0KIyBZIDwtIFkvbm9ybShZLCB0eXBlPSIyIikNCiMgWCA8LSBwNC1wMw0KIyBYIDwtIFgvbm9ybShYLCB0eXBlPSIyIikNCiMgDQojICMgcG9pbnRzKGJveCR4eSUqJVgvdywgMS1ib3gkeHklKiVZL2gsIGNvbD0iZ3JlZW4iKQ0KIyBwIDwtIGJveCR4JSolWCArIGJveCR5JSolWQ0KIyBwb2ludHMocFsxXS93LCAxLXBbMl0vaCwgY29sPSJibHVlIikNCg0KIyBsaW5lcyhyZXAoMC41LCAxMDApLCBzZXEoMC4wMSwgMSwgMC4wMSkpDQoNCiMgcHAgPC0gYyhzZXEoZnJvbT0wKllbMV0sIHRvPTEqWVsxXSwgbGVuZ3RoLm91dCA9IDEwMCksIHNlcShmcm9tPTAqWVsyXSwgdG89MSpZWzJdLCBsZW5ndGgub3V0ID0gMTAwKSkNCiMgIyBwcCA8LSByZXAoMC41KlgsIDEwMCkgKyBjKHNlcShmcm9tPTAqWVsxXSwgdG89MSpZWzFdLCBsZW5ndGgub3V0ID0gMTAwKSwgc2VxKGZyb209MCpZWzJdLCB0bz0xKllbMl0sIGxlbmd0aC5vdXQgPSAxMDApKQ0KIyBsaW5lcyhwcFtzZXEoMSwgMjAwLCBieT0yKV0sIDEtcHBbc2VxKDIsIDIwMCwgYnk9MildKQ0KIyAlKiUNCg0KIyBwbG90KDA6MSwwOjEsdHlwZT0ibiIsYW5uPUZBTFNFLGF4ZXM9RkFMU0UpDQojIGZvciAodCBpbiBzZXEoMCwgMSwgYnk9MC4wMSkpIHsNCiMgdCA8LSBzZXEoMCwgaC8yLCBieT0wLjAxKQ0KIyBzIDwtIHNlcSgwLCB3LzIsIGJ5PTAuMDEpDQojIA0KIyBmb3IgKHQgaW4gc2VxKDAsIGgvMiwgbGVuZ3RoLm91dCA9IDIwKSkgew0KIyAgIGZvciAocyBpbiBzZXEoMCwgdy8yLCBsZW5ndGgub3V0ID0gMjApKSB7DQojICAgICBwIDwtIFkqdCArIFgqcw0KIyAgICAgIyBwIDwtIFkqdA0KIyAgICAgIyBwb2ludHMocFsxXS93ICsgcDNbMV0vdywgMS0ocFsyXSArIHAzWzJdKS9oKQ0KIyAgICAgcG9pbnRzKHBbMV0vdywgLShwWzJdKS9oKQ0KIyAgICAgIyBwb2ludHMocFsxXS93ICsgcDNbMV0vdywgMS0oWVsyXSp0L2ggKyBwM1syXSkvaCkNCiMgICAgICMgcG9pbnRzKFlbMV0qdC93KyBwM1sxXS93LCAxLShZWzJdKnQrIHAzWzJdKS9oKQ0KIyAgIH0NCiMgfQ0KIyBwIDwtIFgqYm94JHggKyBZKmJveCR5DQojICMgIyBwIDwtIFkqdA0KIyBwb2ludHMocFsxXS93LCAtKHBbMl0pL2gsIGNvbD0icHVycGxlIikNCiMgcG9pbnRzKDAvdywgaC9oLCBjb2w9InB1cnBsZSIpDQoNCg0KIyBwb2ludHMoWVsxXSp0L3crIHAzWzFdL3csIDEtKFlbMl0qdCsgcDNbMl0pL2gpDQojIHBvaW50cyhZWzFdKnQvdysgcDNbMV0vdywgMS0oWVsyXSp0KyBwM1syXSkvaCkNCiMgcG9pbnRzKFlbMV0qYm94JHkvdysgcDNbMV0vdywgMS0oWVsyXSpib3gkeSsgcDNbMl0pL2gpDQoNCg0KIyBwb2ludHMoKChwMS1wMylbMV0qdCkvdywgMS0oKHAxLXAzKVsyXSp0KS9oLCBjb2w9ImdyZWVuIikNCiMgfQ0KYGBgDQoNCmBgYHtyfQ0KIyBmcmFtZXMgPC0gMjAwMA0KZnJhbWVzIDwtIHJvdW5kKHNlcSgyLCAxNjAwLCBsZW5ndGgub3V0ID0gMTAwKSkNCiMgYmFja2dyb3VuZCA8LSByZXAoMCwgdypoKjMpDQpqaiA8LSByZWFkSlBFRygiLi9jYXZpYXJfZnJhbWVzL1RocmVlUGFzdFNob3AxY29yMDAwMC5qcGciLG5hdGl2ZT1GQUxTRSkNCmJhY2tncm91bmQgPC0gamogLyBsZW5ndGgoZnJhbWVzKQ0KZm9yIChmIGluIGZyYW1lcykgew0KIyBqaiA8LSByZWFkSlBFRyhwYXN0ZSgiLi9jYXZpYXJfZnJhbWVzL1RocmVlUGFzdFNob3AxY29yIixzdHJyZXAoIjAiLCA0LWxvZzEwKGYtMSArIDEpKSxmLTEsIi5qcGciLCBzZXA9IiIpLCBuYXRpdmU9RkFMU0UpDQogIGpwZyA8LSByZWFkSlBFRyhwYXN0ZSgiLi9jYXZpYXJfZnJhbWVzMi9Ud29FbnRlclNob3AyY29yIixzdHJyZXAoIjAiLCA0LWxvZzEwKGYtMSArIDEpKSxmLTEsIi5qcGciLCBzZXA9IiIpLCBuYXRpdmU9RkFMU0UpDQogICMgZm9yIChpIGluIDE6KHcqaCozKSkgew0KICBmb3IgKGkgaW4gMTpoKSB7DQogICAgZm9yIChqIGluIDE6dykgew0KICAgICAgZm9yIChjIGluIDE6Mykgew0KICAgICAgICBiYWNrZ3JvdW5kW2ksIGosIGNdIDwtIGJhY2tncm91bmRbaSwgaiwgY10gKyBqcGdbaSwgaiwgY10gLyBsZW5ndGgoZnJhbWVzKQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KfQ0KDQpmb3IgKGkgaW4gMTpoKSB7DQogIGZvciAoaiBpbiAxOncpIHsNCiAgICBmb3IgKGMgaW4gMTozKSB7DQogICAgICAgIGJhY2tncm91bmRbaSwgaiwgY10gPC0gbWF4KG1pbihiYWNrZ3JvdW5kW2ksIGosIGNdLCAxKSwgMCkNCiAgICB9DQogIH0NCn0NCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkNCiMgcmFzdGVySW1hZ2UoYmFja2dyb3VuZCwwLDAsMSwxKQ0KcmFzdGVySW1hZ2UoYmFja2dyb3VuZCwwLDAsMSwxKQ0KYGBgDQoNCmBgYHtyfQ0KZm9yIChmIGluIHJvdW5kKHNlcSgyLCAxNjAwLCBsZW5ndGgub3V0ID0gMTApKSkgew0KIyBqaiA8LSByZWFkSlBFRyhwYXN0ZSgiLi9jYXZpYXJfZnJhbWVzL1RocmVlUGFzdFNob3AxY29yIixzdHJyZXAoIjAiLCA0LWxvZzEwKGYtMSArIDEpKSxmLTEsIi5qcGciLCBzZXA9IiIpLCBuYXRpdmU9RkFMU0UpDQpqaiA8LSByZWFkSlBFRyhwYXN0ZSgiLi9jYXZpYXJfZnJhbWVzMi9Ud29FbnRlclNob3AyY29yIixzdHJyZXAoIjAiLCA0LWxvZzEwKGYtMSArIDEpKSxmLTEsIi5qcGciLCBzZXA9IiIpLCBuYXRpdmU9RkFMU0UpDQpwbG90KDA6MSwwOjEsdHlwZT0ibiIsYW5uPUZBTFNFLGF4ZXM9RkFMU0UpDQpyYXN0ZXJJbWFnZShqaiwwLDAsMSwxKQ0KDQppbnRlcnAgPC0gZnVuY3Rpb24oeCkgLTIwKnheNys3MCp4XjYtODQqeF41KzM1KnheNA0KDQpmb3IgKGkgaW4gMTpoKSB7DQogIGZvciAoaiBpbiAxOncpIHsNCiAgICAjIGZvciAoYyBpbiAxOjMpIHsNCiAgICAgICAgIyBqaltpLCBqLCBjXSA8LSBtYXgobWluKGpqW2ksIGosIGNdIC0gYmFja2dyb3VuZFtpLCBqLCBjXSwgMSksIDApDQogICAgICAgICMgampbaSwgaiwgY10gPC0gbWF4KG1pbigtKHN1bShqaltpLCBqLCBjKDEsMiwzKV0pLzMgLSBzdW0oYmFja2dyb3VuZFtpLCBqLCBjKDEsMiwzKV0pLzMpLCAxKSwgMCkNCiAgICAgICAgIyBqaltpLCBqLCBjXSA8LSBtYXgobWluKG1lYW4oampbaSwgaiwgYygxLDIsMyldKSwgMSksIDApDQogICAgICAgICMgampbaSwgaiwgYygxLDIsMyldIDwtIG1heChtaW4oaW50ZXJwKDEtKG1lYW4oampbaSwgaiwgYygxLDIsMyldKS1tZWFuKGJhY2tncm91bmRbaSwgaiwgYygxLDIsMyldKSkpLCAxKSwgMCkNCiAgICAgICAgampbaSwgaiwgYygxLDIsMyldIDwtIG1heChtaW4oDQogICAgICAgICAgIyBpZmVsc2UoYWJzKG1lYW4oampbaSwgaiwgYygxLDIsMyldKS1tZWFuKGJhY2tncm91bmRbaSwgaiwgYygxLDIsMyldKSkgPCAwLjEsIDAsIG1lYW4oampbaSwgaiwgYygxLDIsMyldKSkNCiAgICAgICAgICBpZmVsc2UoYWJzKG1lYW4oampbaSwgaiwgYygxLDIsMyldKS1tZWFuKGJhY2tncm91bmRbaSwgaiwgYygxLDIsMyldKSkgPCAwLjIsIDAsIDEpDQogICAgICAgICwgMSksIDApDQogICAgIyB9DQogIH0NCn0NCg0KcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KcmFzdGVySW1hZ2UoamosMCwwLDEsMSkNCiMgcG9pbnRzKGdyb3VuZF90cnV0aCRmcmFtZVtbMV1dW1sxXV0kbG9jW1sxXV1bLDFdIC8gdywgMS1ncm91bmRfdHJ1dGgkZnJhbWVbWzFdXVtbMV1dJGxvY1tbMV1dWywyXSAvIGgsIGNvbD0icmVkIikNCn0NCiMgcGxvdCgwOjEsMDoxLHR5cGU9Im4iLGFubj1GQUxTRSxheGVzPUZBTFNFKQ0KIyByYXN0ZXJJbWFnZShiYWNrZ3JvdW5kLDAsMCwxLDEpDQpgYGANCg0KYGBge3J9DQojIGxpYnJhcnkobWV0aG9kcykNCg0KIyBmIDwtIDUwMA0KIyBmIDwtIDEyMDANCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkNCnJhc3RlckltYWdlKGJhY2tncm91bmQsMCwwLDEsMSkNCg0KcmVzdWx0IDwtIHhtbFBhcnNlKGZpbGUgPSAiLi9jMmVzMmd0LnhtbCIpDQpyb290bm9kZSA8LSB4bWxSb290KHJlc3VsdCkNCg0KZm9yIChmIGluIHJvdW5kKHNlcSgyLCAxNjAwLCAxKSkpIHsNCiMgamogPC0gcmVhZEpQRUcocGFzdGUoIi4vY2F2aWFyX2ZyYW1lcy9UaHJlZVBhc3RTaG9wMWNvciIsc3RycmVwKCIwIiwgNC1sb2cxMChmLTEgKyAxKSksZi0xLCIuanBnIiwgc2VwPSIiKSwgbmF0aXZlPUZBTFNFKQ0KIyBqaiA8LSByZWFkSlBFRyhwYXN0ZSgiLi9jYXZpYXJfZnJhbWVzMi9Ud29FbnRlclNob3AyY29yIixzdHJyZXAoIjAiLCA0LWxvZzEwKGYtMSArIDEpKSxmLTEsIi5qcGciLCBzZXA9IiIpLCBuYXRpdmU9RkFMU0UpDQoNCiMgcmVzdWx0IDwtIHhtbFBhcnNlKGZpbGUgPSAiLi9jM3BzMWd0LnhtbCIpDQoNCmlzPC0xOmxlbmd0aCh4bWxFbGVtZW50c0J5VGFnTmFtZShyb290bm9kZVtbZl1dW1sxXV0sICJvYmplY3QiKSkNCmZvciAoaSBpbiBpcykgew0KICBhdHRycyA8LSB4bWxBdHRycyhyb290bm9kZVtbZl1dW1sxXV1bW2ldXVtbMl1dKQ0KICBib3ggPC0gbGlzdCgNCiAgICB3PWFzLm51bWVyaWMoYXR0cnNbInciXSksDQogICAgaD1hcy5udW1lcmljKGF0dHJzWyJoIl0pLA0KICAgIHg9YXMubnVtZXJpYyhhdHRyc1sieGMiXSksDQogICAgeT1hcy5udW1lcmljKGF0dHJzWyJ5YyJdKSwNCiAgICB4eSA9IGMoYXMubnVtZXJpYyhhdHRyc1sieGMiXSksIGFzLm51bWVyaWMoYXR0cnNbInljIl0pKQ0KICApDQogICMgYm94DQogIA0KICBwb2ludHMoYm94JHgvdywgMS1ib3gkeS9oKQ0KICANCiAgIyByZWN0KChib3gkeCAtIGJveCR3LzIpIC8gdywgMS0oYm94JHkgLSBib3gkaC8yKSAvIGgsIChib3gkeCArIGJveCR3LzIpL3csIDEtKGJveCR5ICsgYm94JGgvMikvaCkNCn0NCg0KfQ0KDQoNCmBgYA==